package jbitarrays.api;

import javax.annotation.concurrent.NotThreadSafe;

/**
 * A decorator of {@link InfiniteBitArray} that keeps track of its position in
 * the array. It can only be used for one pass through the array (i.e. it can't
 * be reset), but can be {@link #clone()}ed to give a new {@link CrawlerReader}
 * at the same location in the {@link InfiniteBitArray}.
 * 
 * @see CrawlerWriter the counterpart for writing to an {@link InfiniteBitArray}
 * @since 1.0
 */
@NotThreadSafe public interface CrawlerReader {
	/**
	 * Read a single bit and advance this {@link CrawlerReader}'s index into its
	 * {@link InfiniteBitArray}.
	 * 
	 * @return the bit at the {@link CrawlerReader}'s current index into its
	 *         {@link InfiniteBitArray}.
	 * @see InfiniteBitArray#get(int)
	 * @since 1.0
	 */
	public boolean getNext();

	/**
	 * Start writing from the index at this {@link CrawlerReader}'s current
	 * index into the {@link InfiniteBitArray} <b>or later</b> (as
	 * implementations may not have a one-to-one relationship between bits
	 * written to this {@link CrawlerWriter} and bits written back to the
	 * {@link InfiniteBitArray} - check the documentation). Bubbles may be
	 * necessary to preserve invariants that are implementation details of the
	 * {@link CrawlerReader}, but in every case writing bits using a
	 * {@link CrawlerWriter} and then reading them with the corresponding
	 * {@link CrawlerReader} implementation <b>must</b> return exactly the same
	 * sequence of bits.
	 * 
	 * @throws UnsupportedOperationException
	 *             this operation is optional
	 * @return a {@link CrawlerWriter} at the same index into the
	 *         {@link InfiniteBitArray} as this {@link CrawlerReader} is.
	 *         Writing to the returned {@link CrawlerWriter} won't affect the
	 *         index of this {@link CrawlerReader} (and vice versa), but any
	 *         bits written by the {@link CrawlerWriter} will be read by this
	 *         {@link CrawlerReader} (i.e. no copy-on-write semantics).
	 * @see CrawlerWriter#toReader() which may not return a reader on the exact
	 *      index that this reader is on - see main comment for details.
	 * @since 1.0
	 */
	public CrawlerWriter toWriter();

	/**
	 * A helper method for more efficient bulk operations - the implementation
	 * may call {@link InfiniteBitArray#getN(int, int)}.
	 * 
	 * @throws IllegalArgumentException
	 *             if {@code howMany < 0} or {@code howMany > Integer#SIZE}
	 * @see InfiniteBitArray#getN(int, int)
	 * @since 1.0
	 */
	public int getNextN(int howMany) throws IllegalArgumentException;

	/**
	 * Create a new {@link CrawlerReader} at the same position as this
	 * {@link CrawlerReader}.
	 * 
	 * @return a new instance of {@link CrawlerReader} at the same index into
	 *         the {@link InfiniteBitArray} as this {@link CrawlerReader} is.
	 *         Reading from this {@link CrawlerReader} won't affect the returned
	 *         {@link CrawlerReader}, and vice versa.
	 * @since 1.0
	 */
	public CrawlerReader clone();
}